package com.cn.yds.bdy.service.ipml;

import com.cn.yds.bdy.dao.OptRepository;
import com.cn.yds.bdy.dao.TopicRepository;
import com.cn.yds.bdy.dao.UserRepository;
import com.cn.yds.bdy.dao.model.OPtModel;
import com.cn.yds.bdy.dao.model.OptPo;
import com.cn.yds.bdy.dao.model.Topic;
import com.cn.yds.bdy.dao.model.TopicModel;
import com.cn.yds.bdy.dao.model.UserModel;
import com.cn.yds.bdy.enums.TopicStatusEnum;
import com.cn.yds.bdy.service.OptService;
import com.cn.yds.bdy.utils.ComentUtils;
import com.cn.yds.bdy.vo.ChooseTopicResultVo;
import com.cn.yds.bdy.vo.OptChoiceVo;
import com.cn.yds.bdy.vo.SearchParamVo;
import com.cn.yds.bdy.vo.StudentChoiceVo;
import com.cn.yds.bdy.vo.TeacherChoiceVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OptServiceImpl implements OptService {

    @Autowired
    private OptRepository optRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private TopicRepository topicRepository;

    @Override
    @Transactional
    public Integer teacherChoiceStudents(TeacherChoiceVo teacherChoiceVo) {
        Assert.notNull(teacherChoiceVo.getTopicId(), "Topic id must not be null.");
        Assert.notNull(teacherChoiceVo.getStudentId(), "Student id must not be empty");

        UserModel userModel = userRepository.findById(teacherChoiceVo.getStudentId()).orElse(null);
        Assert.notNull(userModel, "Can't find the student,please check.");
        Integer status = optRepository.teacherAccepteStudent(teacherChoiceVo.getStudentId(), teacherChoiceVo.getTopicId());
        if (status != 1) {
            return 0;
        }
        userModel.setChooseStatus(1);
        // update student choose status
        userRepository.save(userModel);

        // reject other students for the topic
        optRepository.rejectOtherStudent(teacherChoiceVo.getStudentId(), teacherChoiceVo.getTopicId());

        // remove the student from other topic choose list
        //optRepository.removeStudentForTopics(teacherChoiceVo.getStudentId(), teacherChoiceVo.getTopicId());

        // update the topic status to completed
        TopicModel topicModel = topicRepository.findById(teacherChoiceVo.getTopicId()).orElse(null);
        if(Objects.nonNull(topicModel)){
            topicModel.setStatus(TopicStatusEnum.DONE.getStatus());
        }
        topicRepository.save(topicModel);
        return 1;
    }

    @Override
    public Integer teacherUpdateStudentsForTopic(TeacherChoiceVo TeacherChoiceVo) {

        List<OPtModel> byTopicId = optRepository.findByTopicId(TeacherChoiceVo.getTopicId());
        byTopicId.forEach(k->k.setStatus(0));
        optRepository.saveAll(byTopicId);

        return 1;
    }

    @Override
    public Integer studentDeleteTopic(StudentChoiceVo studentChoiceVo) {
        Assert.isTrue(!CollectionUtils.isEmpty(studentChoiceVo.getOptIds()),"Opt ids must not be empty");
        // 0 is doing , 1 is finished , 2 is deleted. student only delete the doing topic
        UserModel userModel = userRepository.findById(studentChoiceVo.getStudentId()).orElse(null);
        Assert.notNull(userModel,"Can't find the student,please check.");
        if(userModel.getChooseStatus()==1){
            return 0;
        }

        List<OPtModel> byIdInAndStatus = optRepository.findByIdInAndStatus(studentChoiceVo.getOptIds(), 1);
        byIdInAndStatus.forEach(k-> k.setStatus(0));
        optRepository.saveAll(byIdInAndStatus);
        return 1;
    }

    @Override
    public List<TopicModel> getTopicByTeacherIdAndOpinion(Integer teacherId, Integer opinion) {

        return optRepository.findByTeacherIdAndTeacherOpinion(teacherId,opinion);
    }

    @Override
    public Page<Topic> getSelectedTopics(SearchParamVo searchParam) {
        ComentUtils.isTrueExecute(StringUtils.isEmpty(searchParam.getText()), () -> searchParam.setText(""));
        Pageable of = PageRequest.of(searchParam.getNum()-1, searchParam.getSize(), Sort.Direction.DESC, "createTime");
        Page<Topic> selectedTopic = optRepository.findStudentSelectedTopic(searchParam.getUserId(), searchParam.getText(), of);
        return selectedTopic;
    }

    @Override
    @Transactional
    public ChooseTopicResultVo studentChoiceTopic(StudentChoiceVo studentChoiceVo) {
        ChooseTopicResultVo resultVo = new ChooseTopicResultVo();

        Assert.notEmpty(studentChoiceVo.getTopicIds(),"Topic ids can not empty.");
        log.info("topic ids :{}",studentChoiceVo.getTopicIds());

        // 1.同一课题只能有3个人选择
        List<OPtModel> findSelectedTopics = optRepository.findByTopicIdInAndStatus(studentChoiceVo.getTopicIds(), 1);
        Integer teacherRejectOpinion = -1;
        Map<Integer, List<OPtModel>> findSelectedTopicsMap = findSelectedTopics.stream()
                .filter(k -> !teacherRejectOpinion.equals(k.getTeacherOpinion()))
                .collect(Collectors.groupingBy(k -> k.getTopicId()));
        List<Integer> fullTopicsIds = findSelectedTopicsMap.entrySet().stream()
                .filter(k -> k.getValue().size() > 2).map(k -> k.getKey())
                .collect(Collectors.toList());
        // 去除 满员
        if(!CollectionUtils.isEmpty(fullTopicsIds)){
            studentChoiceVo.getTopicIds().removeAll(fullTopicsIds);
        }



        // 2.在已经选择的课题中不能重复选择同一课程（除非被拒绝）
        List<OptPo> optPos = optRepository.findOptPosByTopicIds(studentChoiceVo.getStudentId());
        List<Integer> choosedTopicIds = optPos.stream()
                .filter(k-> !teacherRejectOpinion.equals(k.getTeacherOpinion()))
                .filter(k -> studentChoiceVo.getTopicIds().contains(k.getTopicId()))
                .map(k -> k.getTopicId()).collect(Collectors.toList());
        // 重复选择课程
        if(!CollectionUtils.isEmpty(choosedTopicIds)){
            studentChoiceVo.getTopicIds().removeAll(choosedTopicIds);
        }


               // 3.一个人一共只能动态选择三个课题
        int haveSelectedSize = choosedTopicIds.size();
        List<Integer> needSaveOPtIds = new ArrayList<>();
        if(haveSelectedSize<3){
            int needSaveSize = 3 - haveSelectedSize;
            if(studentChoiceVo.getTopicIds().size() > needSaveSize){
                needSaveOPtIds=studentChoiceVo.getTopicIds().subList(0,needSaveSize);
            }else{
                needSaveOPtIds=studentChoiceVo.getTopicIds();
            }
        }

        // create entity and save
        List<OPtModel> oPtModels = needSaveOPtIds.stream()
                .map(k->OPtModel.builder().studentId(studentChoiceVo.getStudentId()).status(1).topicId(k)
                            .teacherOpinion(0).build())
                .collect(Collectors.toList());

        optRepository.saveAll(oPtModels);
        resultVo.setFullNum(fullTopicsIds.size());
        resultVo.setDuplicateNum(choosedTopicIds.size());
        resultVo.setSuccessNum(needSaveOPtIds.size());
        resultVo.setSelectedNum(haveSelectedSize);
        return resultVo;
    }

    @Override
    public Integer validateChooseAuth(Integer studentId) {
        // 1.此人是否已经被老师选中;
        // 2.一个人最多动态选择三个课程;
        UserModel userModel = userRepository.findById(studentId).orElse(null);
        Assert.notNull(userModel,"Can't find the student,please check.");
        if(userModel.getChooseStatus()==1){
            return 0;
        }

        List<OPtModel> oPtModels = optRepository.findByStudentIdAndStatus(studentId, 1);
        Integer teacherRejectOpinion = -1;
        oPtModels = oPtModels.stream().filter(k -> !teacherRejectOpinion.equals(k.getTeacherOpinion()))
                .collect(Collectors.toList());
        if(oPtModels.size()>2) {
            return 2;
        }
        return 1;
    }


}
